<template>
  <div>
    <!-- header -->
    <el-row class="sea-table-header">
      <el-col :span="8">
        <!-- 允许设置一个标题-->
        <slot name="title"></slot>

        <!-- 快捷查询 -->
        <el-form @submit.native.prevent="onSubmit" size="small" style="display: inline-block;">
          <el-input v-model="keyword" placeholder="请输入内容" style="width: 200px;margin-right: 6px;"
                    :size="size">
            <template #append>
              <el-button @click="onSubmit" :loading="loading">
                <i class="fa fa-search"></i>
              </el-button>
            </template>
          </el-input>
        </el-form>

        <!-- 按钮区 -->
        <slot name="buttons"></slot>
      </el-col>

      <el-col :span="16" v-if="!disabledForm">
        <div style="width: 100%">
          <div style="width: calc(100% - 76px);float: left;">
            <el-row>
              <el-form ref="form" :model="params" v-show="expand" :inline="true">

                <!-- 输入框区域 -->
                <slot name="input"></slot>

                <el-form-item>
                  <el-button size="small" type="primary" @click="onSubmit" :loading="loading">查询</el-button>
                  <el-button size="small" @click="onReset" :loading="loading">重置</el-button>
                </el-form-item>
              </el-form>
            </el-row>
          </div>

          <!-- 展开按钮 -->
          <div style="width: 76px;float: right;">
            <el-button size="small" title="展开" @click="switchExpand">
              <i :class="expand? 'fa fa-chevron-up' : 'fa fa-chevron-down'"></i>
            </el-button>
          </div>
        </div>
      </el-col>
    </el-row>
    <!-- header -->

    <!-- body -->
    <el-row v-loading="loading">
      <el-col>
        <slot name="list" :list="list"></slot>
      </el-col>
    </el-row>
    <!-- body -->

    <!-- footer -->
    <el-row v-if="pagination" class="sea-table-footer">
      <el-col>
        <el-pagination
            :page-size="limit_" @size-change="handleLimitChange"
            :current-page="page_" @current-change="handlePageChange"
            :total="total" :page-sizes="pageSizes"
            layout="total, sizes, prev, pager, next, jumper"/>
      </el-col>
    </el-row>
    <!-- footer -->
  </div>
</template>
<script>
/* eslint-disable */
import Layers from "@/lang/layers";
import Query from "@/widget/provider/query"
import PageParser from "@/widget/provider/page-parser"

/**
 * 网络请求框架
 *
 * 简单的 box 布局，已经完 header-form 和 footer-pagination 的设计，
 * 后续开发只需要关注 body 部分即可。
 *
 * 当前组件和 el-table 组合，可以达到 sea-table 一样的效果，并且这种组合更优
 */
export default {
    components: {}
    , name: "SeaNetFrame"
    , props: {
        // 数据 url
        url: {type: String, default: undefined},
        // 请求方式
        method: {type: String, default: 'GET'},
        // 值的改变会触发查询
        where: {type: Object, default: Layers.object},
        // 首次查询所需的参数，一般是表单的数值
        params: {type: Object, default: Layers.object},

        // 本地数据，直接指定数据列表
        data: {type: Array, default: undefined},

        // 触发器，数据联动逻辑
        trigger: {type: Function, default: undefined},
        // 按钮组件大小
        size: {type: String, default: 'small'},
        // 禁用表单
        disabledForm: {type: Boolean, default: false},
        // 表单模型
        model: {type: Array, default: undefined},

        // 是否需要分页
        pagination: {type: Boolean, default: true},
        // 页号字段名称
        pageName: {type: String, default: 'page'},
        // 页容量字段名称
        limitName: {type: String, default: 'limit'},
        // 当前页码
        page: {type: Number, default: 1},
        // 每一页容量
        limit: {type: Number, default: 10},
        // 页号
        pageSizes: {type: Array, default: () => [10, 20, 50, 100]},

        // 表格高度，不要带单位
        bodyHeight: {type: [Number, String], default: undefined},

        // 首次自动加载
        autoLoad: {type: Boolean, default: true},
        // 数据查询执行器
        provider: {type: Function, default: Query},
        // 提交表单前置拦截，如果不满足条件，可以阻止表单提交
        intercept: {type: Function, default: undefined},
        // 查询结果格式化
        resultParser: {type: Function, default: PageParser},
    }
    , data() {
        return {
            // 数据总条数
            total: undefined
            // 页面渲染实际使用的数据列表
            , list: this.data

            //页号
            , page_: this.page
            //行数
            , limit_: this.limit

            // 与 where 等效，会参与到表单序列化中
            , where_: undefined
            // 与 where 等效，会参与到表单序列化中
            , params_: undefined
            // 与 where 等效，会参与到表单序列化中
            , attach_: undefined
            // 默认值
            , default_value: {}

            // 数据载入状态条
            , loading: false

            // 展开表单
            , expand: false

            // 关键字
            , keyword: ''
        }
    }, provide() {
        return {
            // 直接通过 provide 提供当前实例，设计子组件的时候，可以很方便地调用 table 相关的功能
            dataTable: this
        }
    }, watch: {
        where: {
            handler: function (val) {
                this.handlerWhere(val);
            }
        }
        /**
         * 页号的变化，会触发页面查询
         */
        , page: {
            handler: function (newValue) {
                this.page_ = newValue;
                this.triggerChange()
            }
        }
        /**
         * 分页容量变化，会触发页面查询
         */
        , limit: {
            handler: function (newValue) {
                this.limit_ = newValue;
                this.triggerChange()
            }
        }
    }, created() {
        // 设置分页
        if (this.pagination) {
            this.attach_ = {page: this.page, limit: this.limit};
        } else {
            this.attach_ = {};
        }

        // 表单初始值
        if(Layers.isNotBlank(this.params)){
            Layers.copy(this.params, this.default_value);
        }

        // 初始化查询条件
        this.where_ = this.where;

        // 表单参数
        this.params_ = this.params;
    }, mounted() {
        // 首次加载的时间尽量延迟，避免界面未完成初始化，就开始加载数据。
        // 没什么特别好的办法，界面是异步加载的，如果表格过早地渲染完成，会产生一些空指针异常。
        this.$nextTick(() => this.firstLoad());
    }, methods: {
        /**
         * 首次载入数据
         *
         * 首次加载是非常特殊的，
         * 需要获取分页、表单等各方的初始化数据，
         * 这些数据分布在各个插槽中，
         *
         * 插槽中的组件，生命周期是不可控的，在调用这个函数的时候，组件可能还没渲染完成，
         *
         * 因此这个函数很容易产生空指针异常，写法上，尽量保证所有数据载入完成。
         */
        firstLoad() {
            if (this.autoLoad && Layers.isNotEmpty(this.url)) {
                this.reload();
            }
        }
        /**
         * 触发查询，分页排序变化
         *
         * 需要有后台做对接
         *
         * @param column 排序变化事件
         */
        , handlerSort(column) {
            this.attach_.sort = encodeURI(column.prop + ' ' + column.order);
            this.reload();
        }
        /**
         * 触发查询，分页发生变化事件
         *
         * @param page 分页数据
         */
        , handlerPage: function (page) {
            this.attach_ = page;
            this.reload();
        }
        /**
         * 触发查询，表单数据发生变化
         *
         * @param params 表单数据
         */
        , handlerParams: function (params) {
            this.params_ = params;
            this.reload();
        }
        /**
         * 触发查询，表单数据发生变化
         *
         * @param where 附加参数
         */
        , handlerWhere: function (where) {
            this.where_ = where;
            this.reload();
        },

        /**
         * 组件内部页码发生变化
         *
         * @params page 页号配置
         */
        handlePageChange(page) {
            this.page_ = page;
            this.triggerChange();
        },
        /**
         * 组件内部分页数发生变化
         *
         * @params limit 页数
         */
        handleLimitChange(limit) {
            this.limit_ = limit;
            this.triggerChange();
        },
        /**
         * 分页变化事件
         */
        triggerChange: function () {
            let ret = {};
            ret[this.pageName] = this.page_;
            ret[this.limitName] = this.limit_;
            this.handlerPage(ret);
        }

        /**
         * 触发查询，分页发生变化事件
         *
         * @param page 分页数据
         */
        , setPage: function (page) {
            this.attach_ = page;
        }
        /**
         * 触发查询，表单数据发生变化
         *
         * @param params 表单数据
         */
        , setParams: function (params) {
            this.params_ = params;
        }
        /**
         * 触发查询，表单数据发生变化
         *
         * @param where 附加参数
         */
        , setWhere: function (where) {
            this.where_ = where;
        }


        /**
         * 展开搜索栏，默认搜索栏处于隐藏状态
         */
        , switchExpand: function () {
            this.expand = !this.expand
        }

        /**
         * 点击了提交按钮
         */
        , onSubmit: function () {
            this.params_.keyword = this.keyword;
            this.reload()
        }

        /**
         * 点击了重置按钮
         */
        , onReset: function () {
            Layers.copy(this.default_value, this.params_);
            this.reload();
        }

        /**
         * 重新载入数据
         *
         * @param values 参数
         */
        , reload: function (values) {
            if (this.loading) {
                return;
            }
            // 构建请求参数
            let params = {};

            // 分页参数
            Layers.copy(this.attach_, params);
            // 表单参数
            Layers.copy(this.params_, params);
            // 额外指定的参数
            Layers.copy(this.where_, params);
            // 微调参数
            Layers.copy(values, params);

            console.log(params)

            let request = {
                url: this.url,
                method: this.method,
                params: params
            }

            // 前置拦截，进行逻辑判断，根据内容决定是否提交
            if (this.intercept !== undefined && this.intercept(request) === false) {
                return;
            }

            // ajax参数
            this.loading = true;
            this.provider(request).then((ret) => {
                let page = this.resultParser(ret);

                this.total = page.total;
                this.list = page.list;
            }).finally(() => {
                this.loading = false;
            })
        }
    }
    // end --
}
</script>
